package com.example.demo.FIlter;

import com.example.demo.entity.CustomUser;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.utils.JwtUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.example.demo.utils.Constants.EXPIRATION_TIME;
import static com.example.demo.utils.Constants.JWT_RENEWAL_TIME;

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {


    private final StringRedisTemplate stringRedisTemplate;

    private final UserMapper userMapper;

    private final JwtUtil jwtUtil;

    public JwtAuthenticationTokenFilter(StringRedisTemplate stringRedisTemplate, UserMapper userMapper, JwtUtil jwtUtil) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.userMapper = userMapper;
        this.jwtUtil = jwtUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authorization = request.getHeader("authorization");
        if (authorization == null || authorization.isBlank() || !authorization.startsWith("Bearer ")) {
            //没有token，直接放行
            filterChain.doFilter(request, response);
            return;
        }
        String token = authorization.substring(7);
        String username = null;
        try {
            // 有可能刚好过期导致拿不到username
            username = stringRedisTemplate.opsForValue().get("user:token:" + token);
        } catch (Exception e) {
            response.addHeader("Token-Expired", "true");
            return;
        }
        // 判断token是否过期
        if (jwtUtil.extractExpire(token) < JWT_RENEWAL_TIME){
            // token在续期条件下,生成新token
            String renewal = null;
            try {
                renewal = jwtUtil.Renewal(token);
                // 保存新token
                stringRedisTemplate.delete("user:token:" + token);
                assert username != null;
                stringRedisTemplate.opsForValue().set("user:token:" + renewal, username);
                stringRedisTemplate.expire("user:token:" +renewal , EXPIRATION_TIME, TimeUnit.MILLISECONDS);
                // 设置到响应头
                response.addHeader("New-Token", renewal);
            } catch (Exception e) {
                // Renewal抛出token过期
                response.addHeader("Token-Expired", "true");
                return;
            }
        }
        // token重颁结束，继续校验流程
        User user = userMapper.getUserByUsername(username);
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(user.getRole()));
        CustomUser customUser = new CustomUser(user, authorities);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(customUser, null, null);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request, response);
    }
}
